import type { ElementSelectors } from '../../lib/abstract'
import type { ComponentStyleIdType } from '../../types/interfaces'
import type { RangeSliderProps } from './types'
import { UIComponent } from '../../lib/abstract'
import { ComponentStyleId } from '../../types/constants'
import { Select } from '../select'
import { styles } from './styles'
import { DEFAULT_RANGE_SLIDER_PROPS } from './types'

export class RangeSlider extends UIComponent<RangeSliderProps> {
  id: string = 'range-slider'
  readonly description: string = '滑块组件'
  readonly styleId: string = ComponentStyleId[this.name]
  private readonly deFaultValue: number
  private selectInstance: Select | null = null
  element: JQuery<HTMLElement> | undefined = undefined

  get name(): ComponentStyleIdType {
    return 'RangeSlider'
  }

  get className(): string {
    return 'custom-range-slider'
  }

  constructor(props: RangeSliderProps) {
    super({
      ...DEFAULT_RANGE_SLIDER_PROPS,
      ...props,
    })
    this.deFaultValue = props.value || 0

    // 注册样式
    this.registerStyles()
  }

  ELEMENT_SELECTORS: ElementSelectors = {
    input: { selector: `#${this.props.id}`, dynamic: false, unique: true },
    display: { selector: `.value-display`, dynamic: false, unique: false },
    stepDown: { selector: `.step-down`, dynamic: false, unique: false },
    stepUp: { selector: `.step-up`, dynamic: false, unique: false },
    select: { selector: `#${this.props.selectOptions?.id}`, dynamic: false, unique: false },
  }

  private getDisplayValue(value: number): string {
    // 自动计算需要显示的小数位数
    const step = this.props.step || 1
    const precision = this.props.precision
      ?? (step % 1 === 0 ? 0 : step.toString().split('.')[1].length)

    return value.toFixed(precision)
  }

  render(): string {
    const { id, label, value, min, max, showValue, step, selectOptions, title, disabled } = this.props
    const displayValue = this.getDisplayValue(value)

    // 如果有下拉框配置，创建 Select 实例
    if (selectOptions && !this.selectInstance) {
      this.selectInstance = new Select({
        id: selectOptions.id,
        label: selectOptions.label,
        options: selectOptions.options,
        selectedValue: selectOptions.selectedValue,
        onChange: selectOptions.onChange,
      })
    }

    return `
      <label for="${id}" title="${title}" >${label}</label>
      <div class="${this.className}">
        <input 
          id="${id}" 
          type="range" 
          min="${min}" 
          max="${max}" 
          value="${value}"
          step="${step}"
          ${disabled ? 'disabled' : ''}
        >
        ${showValue
          ? `
          <div class="slider-controls">
            <span class="value-display">${displayValue}</span>
            ${step !== 1
              ? `
              <div class="step-buttons">
                <button class="step-button step-down" type="button" aria-label="减少">
                  <svg viewBox="0 0 24 24" width="16" height="16">
                    <path d="M19 13H5v-2h14v2z"/>
                  </svg>
                </button>
                <button class="step-button step-up" type="button" aria-label="增加">
                  <svg viewBox="0 0 24 24" width="16" height="16">
                    <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
                  </svg>
                </button>
              </div>
            `
              : ''}
          </div>
        `
          : ''}
        ${selectOptions && this.selectInstance ? `<div class="slider-select-container">${this.selectInstance.render()}</div>` : ''}
      </div>
    `
  }

  /**
   * 获取当前值
   */
  getValue(): string | undefined {
    const $input = this.getElement('input')
    if (!$input) {
      return undefined
    }

    let sliderValue = $input.val() as string
    const selectValue = this.selectInstance?.getValue()

    if (this.props.precision) {
      sliderValue = this.applyPrecision(Number.parseFloat(sliderValue), this.props.precision ?? 2).toString()
    }

    // 使用格式化规则
    if (this.props.valueFormatter) {
      const format = this.props.valueFormatter
      return format
        ? format(Number(sliderValue), selectValue)
        : this.defaultFormat(sliderValue, selectValue)
    }

    // 默认返回原始值
    return sliderValue
  }

  private defaultFormat(sliderValue: string, selectValue?: string): string {
    return selectValue ? `${sliderValue}${selectValue}` : sliderValue.toString()
  }

  private applyPrecision(value: number, precision: number): number {
    return Number.parseFloat(value.toFixed(precision))
  }

  bindEvents(): void {
    const $input = this.getElement('input')
    const step = this.props.step || 1

    if ($input && $input.length) {
      // 更新值显示
      const updateValue = () => {
        const currentValue = Number($input.val())
        this.getElement('display')?.text(this.getDisplayValue(currentValue).toString())
        this.props.onChange?.(currentValue)
      }

      // 步长减少
      this.getElement('stepDown')?.on('click', () => {
        const newValue = Math.max(
          Number($input.val()) - step,
          this.props.min,
        )
        $input.val(newValue).trigger('change')
      })

      // 步长增加
      this.getElement('stepUp')?.on('click', () => {
        const newValue = Math.min(
          Number($input.val()) + step,
          this.props.max,
        )
        $input.val(newValue).trigger('change')
      })

      $input.on('input', updateValue)
      $input.on('change', updateValue)

      // 挂载 Select 组件
      if (this.selectInstance) {
        const $selectContainer = this.$element?.find('.slider-select-container')
        if ($selectContainer)
          this.selectInstance.mount($selectContainer)
      }
    }
  }

  getStyles(): string {
    return styles()
  }

  reset(): void {
    super.reset()

    const value = this.getDisplayValue(this.deFaultValue)
    // 重置滑块值
    this.getElement('input')?.val(value)
    // 重置显示值
    this.getElement('display')?.text(value).toString()
  }

  destroy(): void {
    super.destroy()
    if (this.selectInstance) {
      this.selectInstance.destroy()
      this.selectInstance = null
    }
  }
}
